#pragma once

#include "Requestor.hpp"

namespace bitrpc
{
    namespace client
    {
        class RpcCaller
        {
            //Requestor中的send是针对BaseMessage进行处理的；
            //而RpcCaller中针对结果的处理是针对RpcResponse里的result进行处理的
        public:
            using ptr = std::shared_ptr<RpcCaller>;
            using JsonAsyncResponse = std::future<Json::Value>;
            using JsonResponseCallback = std::function<void(const Json::Value &)>;
            RpcCaller(Requestor::ptr requestor) : _requestor(requestor)
            {
            }
            // 同步调⽤：发起调⽤后，等收到响应结果后返回
            // 所谓的同步调用，其实就是发送请求后，要在本线程获取响应信息的结果信息
 
            bool call(const BaseConnection::ptr &conn, const std::string &method,
                      const Json::Value &params, Json::Value &result)
            {
                // DLOG("开始rpc同步调用……");
                // 1.组织请求
                auto req_msg = MessageFactory::create<RPCRequest>();
                req_msg->SetId(UUID::uuid());
                req_msg->SetMessageType(MessageType::REQ_RPC);
                req_msg->SetMethod(method);
                req_msg->SetParams(params);
                BaseMessage::ptr rsp_msg;

                // 2.发送请求
                bool ret = _requestor->send(conn, std::dynamic_pointer_cast<BaseMessage>(req_msg), rsp_msg);
                if (ret == false)
                {
                    ELOG("同步RPC请求失败");
                    return false;
                }
                // DLOG("收到响应，进行解析，获取结果！");
                
                // 3.等待响应
                auto rpc_rsp_msg = std::dynamic_pointer_cast<RpcResponse>(rsp_msg);
                if (!rpc_rsp_msg)
                {
                    ELOG("rpc响应，向下类型转换失败");
                    return false;
                }
                if (rpc_rsp_msg->rcode() != RCODE::RCODE_OK)
                {
                    ELOG("rpc请求出错，%s", errReason(rpc_rsp_msg->rcode()).c_str());
                    return false;
                }
                result = rpc_rsp_msg->result();
                // DLOG("结果设置完毕……");

                return true;
            }

            // 异步调⽤：发起调⽤后⽴即返回，在想获取结果的时候进⾏获取
            bool call(const BaseConnection::ptr &conn, const std::string &method,
                      const Json::Value &params, JsonAsyncResponse &result)
            {
                DLOG("开始rpc异步调用……");

                // 发送的是异步回调请求，设置回调函数，回调函数中传入一个promise对象，在回调函数中对promise对象设置数据
                // 所谓的异步调用，其实就是发送请求后，要在另一个线程获取响应信息的结果信息
                // 1.组织请求
                auto req_msg = MessageFactory::create<RPCRequest>();
                req_msg->SetId(UUID::uuid());
                req_msg->SetMessageType(MessageType::REQ_RPC);
                req_msg->SetMethod(method);
                req_msg->SetParams(params);
                // std::promise<Json::Value> json_promise;//临时对象，在此异步调用结束后，会释放掉，此时回调函数无法将结果信息传给promise
                // 所以要用shared_ptr来管理promise对象,因为绑定时引用计数会加一
                auto json_promise = std::make_shared<std::promise<Json::Value>>();
                result = json_promise->get_future(); // 当我们的回调函数cb处理完响应，将结果信息保存到json_promise后，我们就能拿到结果了
                auto cb = std::bind(&RpcCaller::Callback, this, json_promise, std::placeholders::_1);
                // 2.发送回调请求
                bool ret = _requestor->send(conn, std::dynamic_pointer_cast<BaseMessage>(req_msg), cb);
                if (ret == false)
                {
                    ELOG("异步调用RPC请求失败");
                    return false;
                }
                return true;
            }
            // 回调调⽤：发起调⽤的同时设置结果的处理回调，收到响应后⾃动对结果进⾏回调处理

            bool call(const BaseConnection::ptr conn, const std::string &method,
                      const Json::Value &params,  JsonResponseCallback cb)
            {
                DLOG("开始rpc回调调用……");

                // 1.组织请求
                auto req_msg = MessageFactory::create<RPCRequest>();
                req_msg->SetId(UUID::uuid());
                req_msg->SetMessageType(MessageType::REQ_RPC);
                req_msg->SetMethod(method);
                req_msg->SetParams(params);
                auto callback = std::bind(&RpcCaller::Callback1, this, cb, std::placeholders::_1);
                // 2.发送回调请求
                bool ret = _requestor->send(conn, std::dynamic_pointer_cast<BaseMessage>(req_msg), callback);
                if (ret == false)
                {
                    ELOG("回调RPC请求失败");
                    return false;
                }
                return true;
            }

        private:
            // 回调中的回调，针对响应信息来处理结果
            bool Callback1(const JsonResponseCallback &cb, const BaseMessage::ptr &msg)
            {
                auto rpc_rsp_msg = std::dynamic_pointer_cast<RpcResponse>(msg);
                if (!rpc_rsp_msg)
                {
                    ELOG("rpc响应，向下类型转换失败");
                    return false;
                }
                if (rpc_rsp_msg->rcode() != RCODE::RCODE_OK)
                {
                    ELOG("rpc请求出错，%s", errReason(rpc_rsp_msg->rcode()).c_str());
                    return false;
                }
                cb(rpc_rsp_msg->result());
                return true;
            }
            // 异步回调：将响应信息的结果信息保存到promise对象
            bool Callback(shared_ptr<std::promise<Json::Value>> &result, const BaseMessage::ptr &msg)
            {
                auto rpc_rsp_msg = std::dynamic_pointer_cast<RpcResponse>(msg);
                if (!rpc_rsp_msg)
                {
                    ELOG("rpc响应，向下类型转换失败");
                    return false;
                }
                if (rpc_rsp_msg->rcode() != RCODE::RCODE_OK)
                {
                    ELOG("rpc请求出错，%s", errReason(rpc_rsp_msg->rcode()).c_str());
                    return false;
                }
                result->set_value(rpc_rsp_msg->result());
                return true;
            }

        private:
            Requestor::ptr _requestor;
        };
    }
}
